#include "matrixsheet.h"
#include "matrixmodel.h"
#include "delegates.h"
#include "matrix.h"
#include "sheetheaderview.h"
#include "thumbnailpainter.h"

#include <QMouseEvent>
#include <QDebug>
#include <QSpinBox>
#include <QLabel>
#include <QThread>

class MatrixSheetPrivate
{
public:
    MatrixSheetPrivate(MatrixSheet* q);
    ~MatrixSheetPrivate();

    MatrixSheet* q_ptr;
    MatrixModel* model = nullptr;
    SheetHeaderView* horizontalHeader = nullptr;
    SheetHeaderView* verticalHeader = nullptr;

    bool isThumbnailsVisible = true;
};

MatrixSheetPrivate::MatrixSheetPrivate(MatrixSheet *q) : q_ptr(q)
{
    model = new MatrixModel;
    q_ptr->setModel(model);
}

MatrixSheetPrivate::~MatrixSheetPrivate()
{
    delete model;
}

MatrixSheet::MatrixSheet(QWidget* parent) : QTableView(parent)
{
    d_ptr = new MatrixSheetPrivate(this);
    this->setAlternatingRowColors(true);

    d_ptr->horizontalHeader = new SheetHeaderView(Qt::Horizontal, this);
    setHorizontalHeader(d_ptr->horizontalHeader);

    d_ptr->verticalHeader = new SheetHeaderView(Qt::Vertical, this);
    setVerticalHeader(d_ptr->verticalHeader);
}

MatrixSheet::~MatrixSheet()
{
    delete d_ptr;
}

void MatrixSheet::setMatrix(const QSharedPointer<MatrixBase>& matrix)
{
    if (matrix) {

        disconnect(matrix.data(), SIGNAL(valueChanged(int,int,QVariant,QVariant)), this,
                   SLOT(onMatrixValueChanged(int,int,QVariant,QVariant)));
        connect(matrix.data(), SIGNAL(valueChanged(int,int,QVariant,QVariant)), this,
                   SLOT(onMatrixValueChanged(int,int,QVariant,QVariant)));

        d_ptr->model->setMatrix(matrix);

        switch (matrix->type()) {
        case MatrixBase::Int:
            setItemDelegate(new SpinBoxDelegate(this));
            break;

        case MatrixBase::Float:
        case MatrixBase::Double:
            setItemDelegate(new DoubleSpinBoxDelegate(this));
            break;

        case MatrixBase::ComplexFloat:
        case MatrixBase::ComplexDouble:
            setItemDelegate(new ComplexSpinBoxDelegate(this));
            break;
        }

        d_ptr->horizontalHeader->setMatrix(matrix.data());
        d_ptr->verticalHeader->setMatrix(matrix.data());

    }
}

QSharedPointer<MatrixBase> MatrixSheet::matrix() const
{
    return d_ptr->model->matrix();
}

void MatrixSheet::setThumbnailsVisible(bool visible)
{
    if (d_ptr->isThumbnailsVisible != visible) {

    }
}

bool MatrixSheet::isThumbnailsVisible() const
{
    return d_ptr->isThumbnailsVisible;
}

void MatrixSheet::setHorizontalHeaderData(const QVector<double>& data)
{
    d_ptr->model->setHorizontalHeaderData(data);
}

QVector<double> MatrixSheet::horizontalHeaderData() const
{
    return d_ptr->model->horizontalHeaderData();
}

void MatrixSheet::setVerticalHeaderData(const QVector<double>& data)
{
    d_ptr->model->setVerticalHeaderData(data);
}

QVector<double> MatrixSheet::verticalHeaderData() const
{
    return d_ptr->model->verticalHeaderData();
}

QSize MatrixSheet::sizeHint() const
{
    return QSize(500, 500);
}

void MatrixSheet::scrollContentsBy(int dx, int dy)
{
    QTableView::scrollContentsBy(dx, dy);
    if (dx != 0) {
        SheetHeaderView* horiHeader = qobject_cast<SheetHeaderView*>(horizontalHeader());
        horiHeader->relayoutDelegates();
    }

    if (dy != 0) {
        SheetHeaderView* verHeader = qobject_cast<SheetHeaderView*>(verticalHeader());
        verHeader->relayoutDelegates();
    }
}

void MatrixSheet::onMatrixValueChanged(int row, int col, const QVariant &oldVal, const QVariant &newVal)
{
    qDebug() << "[" << row << "," << col << "]:{" << oldVal << "," << newVal << "}";
}
